#include "MMesh.h"
#include <time.h>

MMesh::MMesh(void)
{
	name="Mesh";
	bNormal = false;
}


MMesh::~MMesh(void)
{

}

MMesh *MMesh::makeMesh(string strFile) {
	MMesh *rt= new MMesh();
	ifstream fin(strFile);
	if(fin.is_open()) {
		string tmp;
		int i = 0;
		while(fin.good()) {
			getline(fin,tmp);
			vector<string> datav;
			istringstream stm(tmp);
			while(getline(stm,tmp,' ')) {
				datav.push_back(tmp);
			}
			if(datav.empty() || !datav[0].compare("#")) {
				continue;
			}
			try{
				if(!datav[0].compare("v")) {
					rt->vertex.push_back(MVertex(atof(datav[1].data()),atof(datav[2].data()),atof(datav[3].data())));
				}
				else if(!datav[0].compare("vt")) {//texture
					rt->texture.push_back(MVertex(atof(datav[1].data()),atof(datav[2].data()),0));
				}
				else if(!datav[0].compare("vn")) {	//normal
					rt->normal.push_back(MVertex(atof(datav[1].data()),atof(datav[2].data()),atof(datav[3].data())));
				}
				else if(!datav[0].compare("f")) {	//poly surface
					vector<TRIPLE> vntriplelist; 
					for(int i = 1; i<datav.size(); i++) {
						vector<string> vntriple;
						istringstream vnstm(datav[i]);
						string strindex;
						TRIPLE triple;
						while(getline(vnstm,strindex,'/')) {
							vntriple.push_back(strindex);
						}
						for(int j=0;j<vntriple.size();j++) {
							triple.index[j] = atoi(vntriple[j].data())-1;
						}
						vntriplelist.push_back(triple);
					}
					rt->poly.push_back(vntriplelist);
				}
				else {
					cout<<"WTF: "<<datav[0]<<endl;
				}
			}
			catch(const runtime_error &e) {

			}
			i++;
		}
		fin.close();
		//update own axis
		rt->v1 = MVertex(0,-1,0);
		rt->v2 = MVertex(0,1,0);
		return rt;
	}
	else {//can not find file
		fprintf(stderr,"Can not open file: %s \n", strFile);
		return NULL;
	}
}

void MMesh::drawShape() {

}

void MMesh::drawMesh(void(*draw_poly)(const vector<MVertex> &v1, int ic),
		void(*drawline)(const MVertex &p1,  const MVertex &p2,int ic)) {
	int icolor = 5;//rand()%8+1;
	vector<MVertex> vlist;
	for(int i = 0; i<poly.size(); i++) {
		vlist.clear();
		for(int j=0; j<poly[i].size();j++) {
			vlist.push_back(vertex[poly[i][j].index[0]]);
			if(drawline && bNormal) {
				drawline(vertex[poly[i][j].index[0]],vertex[poly[i][j].index[0]]+normal[poly[i][j].index[2]]*NORMALEN,1);
			}
		}
		draw_poly(vlist,icolor);
	}
}


void MMesh::incrementSlice() {

}

void MMesh::decrementSlice() {

}

void MMesh::incrementStack() {

}

void MMesh::decrementStack() {

}


void MMesh::translate(float x, float y, float z) {
	for(vector<MVertex>::iterator  it=vertex.begin(); it!=vertex.end(); it++) {
		*it = (*it).translate(x,y,z);
	}
	v1 = v1.translate(x,y,z);
	v2 = v2.translate(x,y,z);
}

void MMesh::rotate(float deg, int x, int y, int z) {
	float theta = deg/180*PI;
	if(x==1) {
		for(vector<MVertex>::iterator  it=vertex.begin(); it!=vertex.end(); it++) {
			*it = (*it).rotateX(theta);
		}
		for(vector<MVertex>::iterator it=normal.begin(); it!=normal.end(); it++) {
			*it = (*it).rotateX(theta);
		}
		v1 = v1.rotateX(theta);
		v2 = v2.rotateX(theta);
	}
	if(y==1) {
		for(vector<MVertex>::iterator  it=vertex.begin(); it!=vertex.end(); it++) {
			*it = (*it).rotateY(theta);
		}
		for(vector<MVertex>::iterator it=normal.begin(); it!=normal.end(); it++) {
			*it = (*it).rotateY(theta);
		}
		v1 = v1.rotateY(theta);
		v2 = v2.rotateY(theta);
	}
	if(z==1) {
		for(vector<MVertex>::iterator  it=vertex.begin(); it!=vertex.end(); it++) {
			*it = (*it).rotateZ(theta);
		}
		for(vector<MVertex>::iterator it=normal.begin(); it!=normal.end(); it++) {
			*it = (*it).rotateZ(theta);
		}
		v1 = v1.rotateZ(theta);
		v2 = v2.rotateZ(theta);
	}
}

void MMesh::scale(float x, float y, float z){
	for(vector<MVertex>::iterator  it=vertex.begin(); it!=vertex.end(); it++) {
		*it = (*it).scaling(x,y,z);
	}
	v1 = v1.scaling(x,y,z);
	v2 = v2.scaling(x,y,z);
}

void MMesh::rotateAroundOwnAxis(float theta) {
	MMatrix mT, mM, mR, mMb, mTb;
	//set translate matrix
	mT.setMatrix(1,0,0,-v1.point[0],0,1,0,-v1.point[1],0,0,1,-v1.point[2],0,0,0,1);
	//set translate back matrix
	mTb.setMatrix(1,0,0,v1.point[0],0,1,0,v1.point[1],0,0,1,v1.point[2],0,0,0,1);
	//get its own world axis
	MVertex u = getVertex(v1,v2).normailize(); //u match to +x
	MVertex n,v;
	if(isEqual(u.point[0],0) && isEqual(u.point[2],0)) {//if u is the same as up vector
		if(isEqual(u.point[1],1)) {
			n = MVertex(1,0,0);
			v = MVertex(0,0,1);
		}
		else if(isEqual(u.point[1],-1)) {
			n = MVertex(0,0,1);
			v = MVertex(1,0,0);
		}
		else {
			fprintf(stderr,"rotateAroundOwnAxis error\n");
		}
	}
	else {
		n = u.CrossProduct(MVertex(0,1,0)).normailize(); //n match to +z
		v = n.CrossProduct(u).normailize(); //v match to +y
	}
	//set rotation matrix turn vertex from own axis to world axis
	mM.setMatrix(u.point[0], u.point[1], u.point[2], 0,
		v.point[0], v.point[1], v.point[2], 0,
		n.point[0], n.point[1], n.point[2],0,
		0,0,0,1);
	//set rotation matrix turn vertex from world axis to its own world
	mMb.setMatrix(u.point[0], v.point[0], n.point[0], 0,
		u.point[1], v.point[1], n.point[1], 0,
		u.point[2], v.point[2], n.point[2], 0,
		0,0,0,1);
	//set rotation matrix rotate vertex around x axis which is the central axis
	mR.setMatrix(1,0,0,0,
		0,cos(theta),-sin(theta),0,
		0,sin(theta),cos(theta),0,
		0,0,0,1);

	//now, get the final magic matrix
	//matrix = mTb * mMb * mR * mM * mT
	MMatrix normalRotation = mMb.dotMatrix(mR).dotMatrix(mM);
	matrix = mTb.dotMatrix(normalRotation).dotMatrix(mT);
	for(vector<MVertex>::iterator  it=vertex.begin(); it!=vertex.end(); it++) {
		*it = matrix.dotVertex(*it);
	}
	for(vector<MVertex>::iterator it=normal.begin(); it!=normal.end(); it++) {
		*it = normalRotation.dotVertex(*it);
	}
}
